﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WhittleList.Bll;
using WhittleList.Tests.Mocks;
using WhittleList.Tests.Helpers;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace WhittleList.Tests.Repositories
{
    [TestClass]
    public class UserRepositoryTest
    {
        List<FakeUser> data;
        FakeDBContext dbContext;
        UserRepository repository;

        [TestInitialize]
        public void Init()
        {
            data = FakeUser.GetList(10);
            dbContext = new FakeDBContext();
            dbContext.Setup(x => x.Users).Returns(data.Convert());
            repository = new UserRepository(dbContext.Object);
        }

        [TestMethod]
        public void UserRepository_AuthenticateUserTest_InvalidEmail_ReturnsFalse()
        {
            Assert.IsFalse(repository.AuthenticateUser(null, "password"));
        }

        [TestMethod]
        public void UserRepository_AuthenticateUserTest_InvalidPassword_ReturnsFalse()
        {
            data[2].Setup(x => x.AuthenticatePassword("password")).Returns(false);
            Assert.IsFalse(repository.AuthenticateUser(data[2].Object.EmailAddress, "password"));
            data[2].Verify(x => x.AuthenticatePassword("password"), Moq.Times.Once());
        }

        [TestMethod]
        public void UserRepository_AuthenticateUserTest_ValidArgs_ReturnsTrue()
        {
            data[2].Setup(x => x.AuthenticatePassword("password")).Returns(true);
            Assert.IsTrue(repository.AuthenticateUser(data[2].Object.EmailAddress, "password"));
            data[2].Verify(x => x.AuthenticatePassword("password"), Moq.Times.Once());
        }

        [TestMethod]
        public void UserRepository_InsertTest_SetCreatedAndUpdated()
        {
            var tmp = DateTime.Now;

            var user = new User();

            dbContext.Setup(x => x.GetInserts<User>()).Returns(new[] { user });

            repository.Insert(user);
            repository.SaveChanges(user);

            Assert.IsTrue(tmp <= user.Created);
            Assert.IsTrue(tmp <= user.LastUpdated);
            Assert.IsTrue(DateTime.Now >= user.Created);
            Assert.IsTrue(DateTime.Now >= user.LastUpdated);

            dbContext.Verify(x => x.Insert(Moq.It.IsAny<User>()), Moq.Times.Once());
            dbContext.Verify(x => x.SubmitChanges(), Moq.Times.Once());
        }

        [TestMethod]
        [ExpectedException(typeof(WhittleList.Bll.Exceptions.DuplicateEmailException))]
        public void UserRepository_InsertTest_DuplicateEmail_ThrowException()
        {
            var user = new User();
            user.EmailAddress = data[3].Object.EmailAddress;

            dbContext.Setup(x => x.GetInserts<User>()).Returns(new[] { user });

            repository.Insert(user);
            repository.SaveChanges(user);
        }

        [TestMethod]
        [ExpectedException(typeof(WhittleList.Bll.Exceptions.DuplicateEmailException))]
        public void UserRepository_UpdateTest_DuplicateEmail_ThrowException()
        {
            data[4].Object.EmailAddress = data[5].Object.EmailAddress;

            dbContext.Setup(x => x.GetUpdates<User>()).Returns(data.Convert());

            repository.SaveChanges(data[4].Object);
        }

        [TestMethod]
        public void UserRepository_UpdateTest_SetsLastUpdated()
        {
            var tmp = DateTime.Now;
            var user = new User();

            dbContext.Setup(x => x.GetUpdates<User>()).Returns(new [] {user});

            repository.SaveChanges(user);

            dbContext.Verify(x => x.SubmitChanges(), Moq.Times.Once());

            Assert.IsTrue(tmp <= user.LastUpdated);
            Assert.IsTrue(DateTime.Now >= user.LastUpdated);

        }

        [TestMethod]
        public void UserRepository_GetByEmailAddress_InvalidEmailAddress_ReturnsNull()
        {
            Assert.IsNull(repository.GetByEmailAddress("rubbish"));
        }

        [TestMethod]
        public void UserRepository_GetByEmailAddress_ValidEmailAddress_ReturnsCorrectItem()
        {
            var tmp = repository.GetByEmailAddress(data[4].Object.EmailAddress);
            Assert.IsNotNull(tmp);
            Assert.AreEqual(data[4].Object, tmp);
        }
    }
}
